diff --git a/sapl/base/forms.py b/sapl/base/forms.py
index ccd2c132b..ec69c50d9 100644
--- a/sapl/base/forms.py
+++ b/sapl/base/forms.py
@@ -23,6 +23,7 @@ from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
from sapl.audiencia.models import AudienciaPublica,TipoAudienciaPublica
from sapl.comissoes.models import Reuniao, Comissao
from sapl.materia.models import (MateriaLegislativa, UnidadeTramitacao, StatusTramitacao)
+from sapl.norma.models import (NormaJuridica)
from sapl.parlamentares.models import SessaoLegislativa
from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MAX_IMAGE_UPLOAD_SIZE
@@ -688,6 +689,83 @@ class RelatorioAtasFilterSet(django_filters.FilterSet):
)
+class RelatorioNormasMesFilterSet(django_filters.FilterSet):
+
+ ano = django_filters.ChoiceFilter(required=True,
+ label='Ano da Norma',
+ choices=RANGE_ANOS)
+
+ filter_overrides = {models.DateField: {
+ 'filter_class': django_filters.DateFromToRangeFilter,
+ 'extra': lambda f: {
+ 'label': '%s (%s)' % (f.verbose_name, _('Ano')),
+ 'widget': RangeWidgetOverride}
+ }}
+
+
+ class Meta:
+ model = NormaJuridica
+ fields = ['ano']
+
+ def __init__(self, *args, **kwargs):
+ super(RelatorioNormasMesFilterSet, self).__init__(
+ *args, **kwargs)
+
+ self.filters['ano'].label = 'Ano'
+ self.form.fields['ano'].required = True
+
+ row1 = to_row([('ano', 12)])
+
+ self.form.helper = FormHelper()
+ self.form.helper.form_method = 'GET'
+ self.form.helper.layout = Layout(
+ Fieldset(_('Normas por mês do ano.'),
+ row1, form_actions(label='Pesquisar'))
+ )
+
+ @property
+ def qs(self):
+ parent = super(RelatorioNormasMesFilterSet, self).qs
+ return parent.distinct().order_by('data')
+
+
+class RelatorioNormasVigenciaFilterSet(django_filters.FilterSet):
+
+ ano = django_filters.ChoiceFilter(required=True,
+ label='Ano da Norma',
+ choices=RANGE_ANOS)
+
+ vigencia = forms.ChoiceField(
+ label=_('Vigência'),
+ choices=[(True, "Vigente"), (False, "Não vigente")],
+ widget=forms.RadioSelect(),
+ required=True)
+
+
+ def __init__(self, *args, **kwargs):
+ super(RelatorioNormasVigenciaFilterSet, self).__init__(
+ *args, **kwargs)
+
+ self.filters['ano'].label = 'Ano'
+ self.form.fields['ano'].required = True
+ self.form.fields['vigencia'] = self.vigencia
+
+ row1 = to_row([('ano', 12)])
+ row2 = to_row([('vigencia', 12)])
+
+ self.form.helper = FormHelper()
+ self.form.helper.form_method = 'GET'
+ self.form.helper.layout = Layout(
+ Fieldset(_('Normas por vigência.'),
+ row1, row2,
+ form_actions(label='Pesquisar'))
+ )
+
+ @property
+ def qs(self):
+ return qs_override_django_filter(self)
+
+
class RelatorioPresencaSessaoFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
@@ -1061,7 +1139,8 @@ class ConfiguracoesAppForm(ModelForm):
'cronometro_consideracoes',
'mostrar_brasao_painel',
'receber_recibo_proposicao',
- 'assinatura_ata']
+ 'assinatura_ata',
+ 'estatisticas_acesso_normas']
def __init__(self, *args, **kwargs):
super(ConfiguracoesAppForm, self).__init__(*args, **kwargs)
diff --git a/sapl/base/migrations/0027_appconfig_relatorios_atos.py b/sapl/base/migrations/0027_appconfig_relatorios_atos.py
new file mode 100644
index 000000000..afd3382e1
--- /dev/null
+++ b/sapl/base/migrations/0027_appconfig_relatorios_atos.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.8 on 2018-12-11 20:25
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('base', '0026_auto_20181126_1727'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='appconfig',
+ name='relatorios_atos',
+ field=models.CharField(choices=[('S', 'Sim'), ('N', 'Não')], default='N', max_length=1, verbose_name='Relatórios de atos acessados'),
+ ),
+ ]
diff --git a/sapl/base/migrations/0028_appconfig_estatisticas_acesso_normas.py b/sapl/base/migrations/0028_appconfig_estatisticas_acesso_normas.py
new file mode 100644
index 000000000..7a4af06de
--- /dev/null
+++ b/sapl/base/migrations/0028_appconfig_estatisticas_acesso_normas.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.8 on 2018-12-18 17:03
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('base', '0027_appconfig_relatorios_atos'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='appconfig',
+ name='estatisticas_acesso_normas',
+ field=models.CharField(choices=[('S', 'Sim'), ('N', 'Não')], default='N', max_length=1, verbose_name='Estatísticas de acesso a normas'),
+ ),
+ ]
diff --git a/sapl/base/migrations/0029_remove_appconfig_relatorios_atos.py b/sapl/base/migrations/0029_remove_appconfig_relatorios_atos.py
new file mode 100644
index 000000000..fa06b23ac
--- /dev/null
+++ b/sapl/base/migrations/0029_remove_appconfig_relatorios_atos.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.8 on 2018-12-18 18:40
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('base', '0028_appconfig_estatisticas_acesso_normas'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='appconfig',
+ name='relatorios_atos',
+ ),
+ ]
diff --git a/sapl/base/models.py b/sapl/base/models.py
index 5caf8b2c0..343a8db9b 100644
--- a/sapl/base/models.py
+++ b/sapl/base/models.py
@@ -12,6 +12,9 @@ from sapl.utils import (LISTA_DE_UFS, YES_NO_CHOICES,
TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensiva')),
('R', _('Restritiva')))
+RELATORIO_ATOS_ACESSADOS = (('S', _('Sim')),
+ ('N', _('Não')))
+
SEQUENCIA_NUMERACAO = (('A', _('Sequencial por ano')),
('L', _('Sequencial por legislatura')),
('U', _('Sequencial único')))
@@ -84,6 +87,11 @@ class AppConfig(models.Model):
verbose_name=_('Visibilidade dos Documentos Administrativos'),
choices=TIPO_DOCUMENTO_ADMINISTRATIVO, default='O')
+ estatisticas_acesso_normas = models.CharField(
+ max_length=1,
+ verbose_name=_('Estatísticas de acesso a normas'),
+ choices=RELATORIO_ATOS_ACESSADOS, default='N')
+
sequencia_numeracao = models.CharField(
max_length=1,
verbose_name=_('Sequência de numeração'),
diff --git a/sapl/base/urls.py b/sapl/base/urls.py
index 93a5b1cd3..ae4add258 100644
--- a/sapl/base/urls.py
+++ b/sapl/base/urls.py
@@ -23,7 +23,11 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud,
RelatorioMateriasPorAutorView,
RelatorioMateriasTramitacaoView,
RelatorioPresencaSessaoView,
- RelatorioReuniaoView, SaplSearchView)
+ RelatorioReuniaoView, SaplSearchView,
+ RelatorioNormasPublicadasMesView,
+ RelatorioNormasVigenciaView,
+ EstatisticasAcessoNormas,
+ RelatoriosListView)
app_name = AppConfig.name
@@ -84,10 +88,16 @@ urlpatterns = [
url(r'^sistema/app-config/', include(AppConfigCrud.get_urls())),
# TODO mover estas telas para a app 'relatorios'
- url(r'^sistema/relatorios/$', TemplateView.as_view(
- template_name='base/relatorios_list.html'), name='relatorios_list'),
+ url(r'^sistema/relatorios/$',
+ RelatoriosListView.as_view(), name='relatorios_list'),
url(r'^sistema/relatorios/materia-por-autor$',
RelatorioMateriasPorAutorView.as_view(), name='materia_por_autor'),
+ url(r'^sistema/relatorios/relatorio-por-mes$',
+ RelatorioNormasPublicadasMesView.as_view(), name='normas_por_mes'),
+ url(r'^sistema/relatorios/relatorio-por-vigencia$',
+ RelatorioNormasVigenciaView.as_view(), name='normas_por_vigencia'),
+ url(r'^sistema/relatorios/estatisticas-acesso$',
+ EstatisticasAcessoNormas.as_view(), name='estatisticas_acesso'),
url(r'^sistema/relatorios/materia-por-ano-autor-tipo$',
RelatorioMateriasPorAnoAutorTipoView.as_view(),
name='materia_por_ano_autor_tipo'),
diff --git a/sapl/base/views.py b/sapl/base/views.py
index ca122ce9f..599d6b05f 100644
--- a/sapl/base/views.py
+++ b/sapl/base/views.py
@@ -1,3 +1,5 @@
+import collections
+import datetime
import logging
import os
@@ -30,6 +32,7 @@ from sapl.comissoes.models import Reuniao, Comissao
from sapl.crud.base import CrudAux, make_pagination
from sapl.materia.models import (Autoria, MateriaLegislativa,
TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao)
+from sapl.norma.models import (NormaJuridica, NormaEstatisticas)
from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca)
from sapl.utils import (parlamentares_ativos,
@@ -45,7 +48,8 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm,
RelatorioMateriasTramitacaoilterSet,
RelatorioPresencaSessaoFilterSet,
RelatorioReuniaoFilterSet, UsuarioCreateForm,
- UsuarioEditForm)
+ UsuarioEditForm, RelatorioNormasMesFilterSet,
+ RelatorioNormasVigenciaFilterSet)
from .models import AppConfig, CasaLegislativa
@@ -276,6 +280,20 @@ class AutorCrud(CrudAux):
return url_reverse
+class RelatoriosListView(TemplateView):
+ template_name='base/relatorios_list.html'
+
+ def get_context_data(self, **kwargs):
+ context = super(TemplateView, self).get_context_data(**kwargs)
+ estatisticas_acesso_normas = AppConfig.objects.first().estatisticas_acesso_normas
+ if estatisticas_acesso_normas == 'S':
+ context['estatisticas_acesso_normas'] = True
+ else:
+ context['estatisticas_acesso_normas'] = False
+
+ return context
+
+
class RelatorioAtasView(FilterView):
model = SessaoPlenaria
filterset_class = RelatorioAtasFilterSet
@@ -744,6 +762,145 @@ class RelatorioMateriasPorAutorView(FilterView):
return context
+class RelatorioNormasPublicadasMesView(FilterView):
+ model = NormaJuridica
+ filterset_class = RelatorioNormasMesFilterSet
+ template_name = 'base/RelatorioNormaMes_filter.html'
+
+ def get_context_data(self, **kwargs):
+ context = super(RelatorioNormasPublicadasMesView,
+ self).get_context_data(**kwargs)
+ context['title'] = _('Normas')
+
+ # Verifica se os campos foram preenchidos
+ if not self.filterset.form.is_valid():
+ return context
+
+ qr = self.request.GET.copy()
+ context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
+
+ context['show_results'] = show_results_filter_set(qr)
+ context['ano'] = self.request.GET['ano']
+
+ 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 norma in context['object_list']:
+ if not meses[norma.data.month] in normas_mes:
+ normas_mes[meses[norma.data.month]] = []
+ normas_mes[meses[norma.data.month]].append(norma)
+
+ context['normas_mes'] = normas_mes
+
+ quant_normas_mes = {}
+ for key in normas_mes.keys():
+ quant_normas_mes[key] = len(normas_mes[key])
+
+ context['quant_normas_mes'] = quant_normas_mes
+
+ return context
+
+
+class RelatorioNormasVigenciaView(FilterView):
+ model = NormaJuridica
+ filterset_class = RelatorioNormasVigenciaFilterSet
+ template_name = 'base/RelatorioNormasVigencia_filter.html'
+
+ def get_filterset_kwargs(self, filterset_class):
+ super(RelatorioNormasVigenciaView,
+ self).get_filterset_kwargs(filterset_class)
+
+ kwargs = {'data': self.request.GET or None}
+ qs = self.get_queryset().order_by('data').distinct()
+ if kwargs['data']:
+ ano = kwargs['data']['ano']
+ vigencia = kwargs['data']['vigencia']
+ qs = qs.filter(ano=ano)
+ if vigencia == 'True':
+ qs_dt_not_null = qs.filter(data_vigencia__isnull=True)
+ qs = (qs_dt_not_null | qs.filter(data_vigencia__gte=datetime.datetime.now().date())).distinct()
+ else:
+ qs = qs.filter(data_vigencia__lt=datetime.datetime.now().date())
+
+ kwargs.update({
+ 'queryset': qs
+ })
+ return kwargs
+
+
+ def get_context_data(self, **kwargs):
+ context = super(RelatorioNormasVigenciaView,
+ self).get_context_data(**kwargs)
+ context['title'] = _('Normas por vigência')
+
+ # Verifica se os campos foram preenchidos
+ if not self.filterset.form.is_valid():
+ return context
+
+ normas_totais = NormaJuridica.objects.filter(ano=self.request.GET['ano'])
+
+ context['quant_total'] = len(normas_totais)
+ if self.request.GET['vigencia'] == 'True':
+ context['vigencia'] = 'Vigente'
+ context['quant_vigente'] = len(context['object_list'])
+ context['quant_nao_vigente'] = context['quant_total'] - context['quant_vigente']
+ else:
+ context['vigencia'] = 'Não vigente'
+ context['quant_nao_vigente'] = len(context['object_list'])
+ context['quant_vigente'] = context['quant_total'] - context['quant_nao_vigente']
+
+ qr = self.request.GET.copy()
+ context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
+
+ context['show_results'] = show_results_filter_set(qr)
+ context['ano'] = self.request.GET['ano']
+
+ return context
+
+
+class EstatisticasAcessoNormas(FilterView):
+ model = NormaJuridica
+ filterset_class = RelatorioNormasMesFilterSet
+ template_name = 'base/EstatisticasAcessoNormas_filter.html'
+
+ def get_context_data(self, **kwargs):
+ context = super(EstatisticasAcessoNormas,
+ self).get_context_data(**kwargs)
+ context['title'] = _('Normas')
+
+ # Verifica se os campos foram preenchidos
+ if not self.filterset.form.is_valid():
+ return context
+
+ qr = self.request.GET.copy()
+ context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
+
+ context['show_results'] = show_results_filter_set(qr)
+ context['ano'] = self.request.GET['ano']
+
+ 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 norma in context['object_list']:
+ if not meses[norma.data.month] in normas_mes:
+ normas_mes[meses[norma.data.month]] = []
+ norma_est = [norma, len(NormaEstatisticas.objects.filter(norma=norma))]
+ normas_mes[meses[norma.data.month]].append(norma_est)
+
+ meses_sem_acesso = []
+ # 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]
+ if all(v[1]==0 for v in normas_mes[n]):
+ meses_sem_acesso.append(n)
+
+ context['normas_mes'] = normas_mes
+ context['meses_sem_acesso'] = meses_sem_acesso
+
+ return context
+
+
class ListarUsuarioView(PermissionRequiredMixin, ListView):
model = get_user_model()
template_name = 'auth/user_list.html'
diff --git a/sapl/norma/migrations/0017_normaestatisticas.py b/sapl/norma/migrations/0017_normaestatisticas.py
new file mode 100644
index 000000000..03009eeec
--- /dev/null
+++ b/sapl/norma/migrations/0017_normaestatisticas.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.8 on 2018-12-17 18:44
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('norma', '0016_tipovinculonormajuridica_revoga_integramente'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='NormaEstatisticas',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('usuario', models.CharField(max_length=50)),
+ ('horario_acesso', models.DateTimeField(auto_now=True, null=True)),
+ ('norma', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='norma.NormaJuridica')),
+ ],
+ ),
+ ]
diff --git a/sapl/norma/models.py b/sapl/norma/models.py
index 6565304ee..80075f113 100644
--- a/sapl/norma/models.py
+++ b/sapl/norma/models.py
@@ -191,6 +191,18 @@ class NormaJuridica(models.Model):
update_fields=update_fields)
+class NormaEstatisticas(models.Model):
+ usuario = models.CharField(max_length=50)
+ horario_acesso = models.DateTimeField(
+ blank=True, null=True,
+ auto_now=True)
+ norma = models.ForeignKey(NormaJuridica,
+ on_delete=models.CASCADE)
+ def __str__(self):
+ return _('Usuário: %(usuario)s, Norma: %(norma)s') % {
+ 'usuario': self.usuario, 'norma': self.norma}
+
+
@reversion.register()
class AutoriaNorma(models.Model):
autor = models.ForeignKey(Autor,
diff --git a/sapl/norma/tests/test_norma.py b/sapl/norma/tests/test_norma.py
index 6603d7167..5c2a76a6a 100644
--- a/sapl/norma/tests/test_norma.py
+++ b/sapl/norma/tests/test_norma.py
@@ -7,6 +7,7 @@ from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.norma.forms import (NormaJuridicaForm, NormaPesquisaSimplesForm,
NormaRelacionadaForm)
from sapl.norma.models import NormaJuridica, TipoNormaJuridica
+from sapl.base.models import AppConfig
@pytest.mark.django_db(transaction=False)
@@ -15,6 +16,7 @@ def test_incluir_norma_submit(admin_client):
tipo = mommy.make(TipoNormaJuridica,
sigla='T',
descricao='Teste')
+ config = mommy.make(AppConfig)
# Testa POST
response = admin_client.post(reverse('sapl.norma:normajuridica_create'),
diff --git a/sapl/norma/views.py b/sapl/norma/views.py
index f2dfb6f2e..f7800c42f 100644
--- a/sapl/norma/views.py
+++ b/sapl/norma/views.py
@@ -1,6 +1,8 @@
-import re
import logging
+import re
+import sapl
+import weasyprint
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist
@@ -13,8 +15,6 @@ from django.views.generic import TemplateView, UpdateView
from django.views.generic.base import RedirectView
from django.views.generic.edit import FormView
from django_filters.views import FilterView
-import weasyprint
-import sapl
from sapl.base.models import AppConfig
from sapl.compilacao.views import IntegracaoTaView
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
@@ -24,7 +24,7 @@ from sapl.utils import show_results_filter_set
from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm,
NormaPesquisaSimplesForm, NormaRelacionadaForm, AutoriaNormaForm)
from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada,
- TipoNormaJuridica, TipoVinculoNormaJuridica, AutoriaNorma)
+ TipoNormaJuridica, TipoVinculoNormaJuridica, AutoriaNorma, NormaEstatisticas)
# LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '')
@@ -190,7 +190,13 @@ class NormaCrud(Crud):
return reverse('%s:%s' % (namespace, 'norma_pesquisa'))
class DetailView(Crud.DetailView):
- pass
+ def get(self, request, *args, **kwargs):
+ estatisticas_acesso_normas = AppConfig.objects.first().estatisticas_acesso_normas
+ if estatisticas_acesso_normas == 'S':
+ NormaEstatisticas.objects.create(usuario=str(self.request.user),
+ norma_id=kwargs['pk'])
+ return super().get(request, *args, **kwargs)
+
class DeleteView(Crud.DeleteView):
@@ -225,7 +231,7 @@ class NormaCrud(Crud):
class ListView(Crud.ListView, RedirectView):
def get_redirect_url(self, *args, **kwargs):
- namespace = self.model._meta.app_config.name
+ namespace = self.model._meta.app_config.name
return reverse('%s:%s' % (namespace, 'norma_pesquisa'))
def get(self, request, *args, **kwargs):
diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py
index aa691da5e..f9b63fd4b 100644
--- a/sapl/rules/map_rules.py
+++ b/sapl/rules/map_rules.py
@@ -139,6 +139,7 @@ rules_group_norma = {
(norma.NormaRelacionada, __base__),
(norma.AnexoNormaJuridica, __base__),
(norma.AutoriaNorma, __base__),
+ (norma.NormaEstatisticas, __base__),
# Publicacao está com permissão apenas para norma e não para matéria
# e proposições apenas por análise do contexto, não é uma limitação
@@ -242,6 +243,7 @@ rules_group_geral = {
(norma.AssuntoNorma, __base__),
(norma.TipoNormaJuridica, __base__),
(norma.TipoVinculoNormaJuridica, __base__),
+ (norma.NormaEstatisticas, __base__),
(parlamentares.Legislatura, __base__),
(parlamentares.SessaoLegislativa, __base__),
diff --git a/sapl/templates/base/EstatisticasAcessoNormas_filter.html b/sapl/templates/base/EstatisticasAcessoNormas_filter.html
new file mode 100644
index 000000000..a8246e22d
--- /dev/null
+++ b/sapl/templates/base/EstatisticasAcessoNormas_filter.html
@@ -0,0 +1,64 @@
+{% extends "crud/list.html" %}
+{% load i18n %}
+{% load crispy_forms_tags %}
+
+{% block base_content %}
+ {% if not show_results %}
+ {% crispy filter.form %}
+ {% endif %}
+ {% if show_results %}
+
+
+ PARÂMETROS DE PESQUISA:
+ Ano: {{ ano }}
+
+ {% if normas_mes|length == 0 %}
+
+ {% trans 'Não foi encontrada nenhuma norma com os parâmetros buscados.'%}
+ {% elif normas_mes|length == meses_sem_acesso|length %}
+
+ {% trans 'Nenhuma norma teve acesso neste ano.'%}
+ {% else %}
+ {% for mes, normas in normas_mes.items %}
+
+
+
+
+ Mês: {{ mes }} |
+
+
+
+ {% if not mes in meses_sem_acesso %}
+
+ {% else %}
+
{% trans 'Nenhuma norma deste mês teve acessos.'%}
+
+ {% endif %}
+
+ {% endfor %}
+ {% endif %}
+ {% endif %}
+{% endblock base_content %}
diff --git a/sapl/templates/base/RelatorioHistoricoTramitacao_filter.html b/sapl/templates/base/RelatorioHistoricoTramitacao_filter.html
index cca46d3ad..1151cd094 100644
--- a/sapl/templates/base/RelatorioHistoricoTramitacao_filter.html
+++ b/sapl/templates/base/RelatorioHistoricoTramitacao_filter.html
@@ -30,7 +30,7 @@
{{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
|
- {{materia.ementa}} |
+ {{materia.ementa}} {{materia.observacao}} |
{% endfor %}
diff --git a/sapl/templates/base/RelatorioMateriasPorAutor_filter.html b/sapl/templates/base/RelatorioMateriasPorAutor_filter.html
index 6a8ed41a8..35e9aa50c 100644
--- a/sapl/templates/base/RelatorioMateriasPorAutor_filter.html
+++ b/sapl/templates/base/RelatorioMateriasPorAutor_filter.html
@@ -51,7 +51,7 @@
{{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
|
- {% autoescape off %}{{materia.ementa}}{% endautoescape %} |
+ {% autoescape off %}{{materia.ementa}} {{materia.observacao}}{% endautoescape %} |
{% if materia.autoria_set.first != materia.autoria_set.last %}
{% for autor in materia.autoria_set.all %}
diff --git a/sapl/templates/base/RelatorioNormaMes_filter.html b/sapl/templates/base/RelatorioNormaMes_filter.html
new file mode 100644
index 000000000..d4f8d5b30
--- /dev/null
+++ b/sapl/templates/base/RelatorioNormaMes_filter.html
@@ -0,0 +1,67 @@
+{% extends "crud/list.html" %}
+{% load i18n %}
+{% load crispy_forms_tags %}
+
+{% block base_content %}
+ {% if not show_results %}
+ {% crispy filter.form %}
+ {% endif %}
+
+ {% if show_results %}
+
+
+ PARÂMETROS DE PESQUISA:
+ Ano: {{ ano }}
+
+ {% if normas_mes|length == 0 %}
+
+ {% trans 'Não foi encontrada nenhuma norma com os parâmetros buscados.'%}
+ {% endif %}
+ {% for mes, normas in normas_mes.items %}
+
+
+
+
+ Mês: {{ mes }} |
+
+
+
+
+
+
+ {% for k, v in quant_normas_mes.items %}
+ {% if k == mes %}
+ {% if v > 1 %}
+ Quantidade encontrada no mês: {{ v }} normas. |
+ {% else %}
+ Quantidade encontrada no mês: 1 norma. |
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+
+
+
+
+
+ {% endfor %}
+ {% endif %}
+{% endblock base_content %}
diff --git a/sapl/templates/base/RelatorioNormasVigencia_filter.html b/sapl/templates/base/RelatorioNormasVigencia_filter.html
new file mode 100644
index 000000000..6412b5b20
--- /dev/null
+++ b/sapl/templates/base/RelatorioNormasVigencia_filter.html
@@ -0,0 +1,57 @@
+{% extends "crud/list.html" %}
+{% load i18n %}
+{% load crispy_forms_tags %}
+
+{% block base_content %}
+ {% if not show_results %}
+ {% crispy filter.form %}
+ {% endif %}
+
+ {% if show_results %}
+
+
+ PARÂMETROS DE PESQUISA:
+ Ano: {{ ano }}
+ Vigência: {{ vigencia }}
+ {% if object_list %}
+
+ {% if object_list|length > 1 %}
+ Foram encontradas {{object_list|length}} normas.
+ {% else %}
+ Foi encontrada 1 norma.
+ {% endif %}
+
+
+ {% else %}
+
+
+
+ Não foi encontrada nenhuma norma com os parâmetros buscados. |
+
+
+
+ {% endif %}
+
+ Estatísticas das normas do ano:
+ {{quant_vigente}} vigente(s) / {{quant_nao_vigente}} não vigente(s)
+ {% endif %}
+{% endblock base_content %}
diff --git a/sapl/templates/base/layouts.yaml b/sapl/templates/base/layouts.yaml
index ef1e53d2a..4f6bbd45d 100644
--- a/sapl/templates/base/layouts.yaml
+++ b/sapl/templates/base/layouts.yaml
@@ -23,6 +23,9 @@ AppConfig:
{% trans 'Textos Articulados' %}:
- texto_articulado_proposicao texto_articulado_materia texto_articulado_norma
+ {% trans 'Estatísticas de acesso' %}:
+ - estatisticas_acesso_normas
+
{% trans 'Assinaturas' %}:
- assinatura_ata
diff --git a/sapl/templates/base/relatorios_list.html b/sapl/templates/base/relatorios_list.html
index 78192855a..87f8933be 100644
--- a/sapl/templates/base/relatorios_list.html
+++ b/sapl/templates/base/relatorios_list.html
@@ -48,6 +48,20 @@
| Audiência Pública |
Audiência Pública com o tipo. |
+
+ Normas por mês |
+ Normas publicadas por mês. |
+
+
+ Normas por vigência |
+ Normas vigentes ou não vigentes. |
+
+ {% if estatisticas_acesso_normas %}
+
+ Estatísticas de acesso de Normas. |
+ Normas por acesso. |
+
+ {% endif %}