Browse Source

Fix #2313 - Geração de relatórios e estatisticas (#2429)

* Colocando opcao de geracao de relatorios em configuracao do sistema

* fix 2313

* HOT-FIX: adiciona logging de erros não tratados

* HOT-FIX: diminui o nível do logging

* inicio do relatorio por mes das normas

* normas por mes concluida e inicio normas vigencia

* relatorio por vigencia em andamento

* adicionadas normas por vigencia

* estatisticas das normas por vigencia por ano

* tela de estatisticas

* adiciona model NormaEstatisticas no map_rules

* correcoes e adicao de opcao no configuracao de aplicacao

* correcao do teste em norma

* retira config relatorio atos que não era utilizado

* migration
pull/2179/head
Cesar Augusto de Carvalho 6 years ago
committed by Edward
parent
commit
62e82aefd2
  1. 81
      sapl/base/forms.py
  2. 20
      sapl/base/migrations/0027_appconfig_relatorios_atos.py
  3. 20
      sapl/base/migrations/0028_appconfig_estatisticas_acesso_normas.py
  4. 19
      sapl/base/migrations/0029_remove_appconfig_relatorios_atos.py
  5. 8
      sapl/base/models.py
  6. 16
      sapl/base/urls.py
  7. 159
      sapl/base/views.py
  8. 25
      sapl/norma/migrations/0017_normaestatisticas.py
  9. 12
      sapl/norma/models.py
  10. 2
      sapl/norma/tests/test_norma.py
  11. 18
      sapl/norma/views.py
  12. 2
      sapl/rules/map_rules.py
  13. 64
      sapl/templates/base/EstatisticasAcessoNormas_filter.html
  14. 2
      sapl/templates/base/RelatorioHistoricoTramitacao_filter.html
  15. 2
      sapl/templates/base/RelatorioMateriasPorAutor_filter.html
  16. 67
      sapl/templates/base/RelatorioNormaMes_filter.html
  17. 57
      sapl/templates/base/RelatorioNormasVigencia_filter.html
  18. 3
      sapl/templates/base/layouts.yaml
  19. 14
      sapl/templates/base/relatorios_list.html

81
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.audiencia.models import AudienciaPublica,TipoAudienciaPublica
from sapl.comissoes.models import Reuniao, Comissao from sapl.comissoes.models import Reuniao, Comissao
from sapl.materia.models import (MateriaLegislativa, UnidadeTramitacao, StatusTramitacao) from sapl.materia.models import (MateriaLegislativa, UnidadeTramitacao, StatusTramitacao)
from sapl.norma.models import (NormaJuridica)
from sapl.parlamentares.models import SessaoLegislativa from sapl.parlamentares.models import SessaoLegislativa
from sapl.sessao.models import SessaoPlenaria from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MAX_IMAGE_UPLOAD_SIZE 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): class RelatorioPresencaSessaoFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: { filter_overrides = {models.DateField: {
@ -1061,7 +1139,8 @@ class ConfiguracoesAppForm(ModelForm):
'cronometro_consideracoes', 'cronometro_consideracoes',
'mostrar_brasao_painel', 'mostrar_brasao_painel',
'receber_recibo_proposicao', 'receber_recibo_proposicao',
'assinatura_ata'] 'assinatura_ata',
'estatisticas_acesso_normas']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ConfiguracoesAppForm, self).__init__(*args, **kwargs) super(ConfiguracoesAppForm, self).__init__(*args, **kwargs)

20
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'),
),
]

20
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'),
),
]

19
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',
),
]

8
sapl/base/models.py

@ -12,6 +12,9 @@ from sapl.utils import (LISTA_DE_UFS, YES_NO_CHOICES,
TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensiva')), TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensiva')),
('R', _('Restritiva'))) ('R', _('Restritiva')))
RELATORIO_ATOS_ACESSADOS = (('S', _('Sim')),
('N', _('Não')))
SEQUENCIA_NUMERACAO = (('A', _('Sequencial por ano')), SEQUENCIA_NUMERACAO = (('A', _('Sequencial por ano')),
('L', _('Sequencial por legislatura')), ('L', _('Sequencial por legislatura')),
('U', _('Sequencial único'))) ('U', _('Sequencial único')))
@ -84,6 +87,11 @@ class AppConfig(models.Model):
verbose_name=_('Visibilidade dos Documentos Administrativos'), verbose_name=_('Visibilidade dos Documentos Administrativos'),
choices=TIPO_DOCUMENTO_ADMINISTRATIVO, default='O') 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( sequencia_numeracao = models.CharField(
max_length=1, max_length=1,
verbose_name=_('Sequência de numeração'), verbose_name=_('Sequência de numeração'),

16
sapl/base/urls.py

@ -23,7 +23,11 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud,
RelatorioMateriasPorAutorView, RelatorioMateriasPorAutorView,
RelatorioMateriasTramitacaoView, RelatorioMateriasTramitacaoView,
RelatorioPresencaSessaoView, RelatorioPresencaSessaoView,
RelatorioReuniaoView, SaplSearchView) RelatorioReuniaoView, SaplSearchView,
RelatorioNormasPublicadasMesView,
RelatorioNormasVigenciaView,
EstatisticasAcessoNormas,
RelatoriosListView)
app_name = AppConfig.name app_name = AppConfig.name
@ -84,10 +88,16 @@ urlpatterns = [
url(r'^sistema/app-config/', include(AppConfigCrud.get_urls())), url(r'^sistema/app-config/', include(AppConfigCrud.get_urls())),
# TODO mover estas telas para a app 'relatorios' # TODO mover estas telas para a app 'relatorios'
url(r'^sistema/relatorios/$', TemplateView.as_view( url(r'^sistema/relatorios/$',
template_name='base/relatorios_list.html'), name='relatorios_list'), RelatoriosListView.as_view(), name='relatorios_list'),
url(r'^sistema/relatorios/materia-por-autor$', url(r'^sistema/relatorios/materia-por-autor$',
RelatorioMateriasPorAutorView.as_view(), name='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$', url(r'^sistema/relatorios/materia-por-ano-autor-tipo$',
RelatorioMateriasPorAnoAutorTipoView.as_view(), RelatorioMateriasPorAnoAutorTipoView.as_view(),
name='materia_por_ano_autor_tipo'), name='materia_por_ano_autor_tipo'),

159
sapl/base/views.py

@ -1,3 +1,5 @@
import collections
import datetime
import logging import logging
import os import os
@ -30,6 +32,7 @@ from sapl.comissoes.models import Reuniao, Comissao
from sapl.crud.base import CrudAux, make_pagination from sapl.crud.base import CrudAux, make_pagination
from sapl.materia.models import (Autoria, MateriaLegislativa, from sapl.materia.models import (Autoria, MateriaLegislativa,
TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao) TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao)
from sapl.norma.models import (NormaJuridica, NormaEstatisticas)
from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca) SessaoPlenariaPresenca)
from sapl.utils import (parlamentares_ativos, from sapl.utils import (parlamentares_ativos,
@ -45,7 +48,8 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm,
RelatorioMateriasTramitacaoilterSet, RelatorioMateriasTramitacaoilterSet,
RelatorioPresencaSessaoFilterSet, RelatorioPresencaSessaoFilterSet,
RelatorioReuniaoFilterSet, UsuarioCreateForm, RelatorioReuniaoFilterSet, UsuarioCreateForm,
UsuarioEditForm) UsuarioEditForm, RelatorioNormasMesFilterSet,
RelatorioNormasVigenciaFilterSet)
from .models import AppConfig, CasaLegislativa from .models import AppConfig, CasaLegislativa
@ -276,6 +280,20 @@ class AutorCrud(CrudAux):
return url_reverse 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): class RelatorioAtasView(FilterView):
model = SessaoPlenaria model = SessaoPlenaria
filterset_class = RelatorioAtasFilterSet filterset_class = RelatorioAtasFilterSet
@ -744,6 +762,145 @@ class RelatorioMateriasPorAutorView(FilterView):
return context 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): class ListarUsuarioView(PermissionRequiredMixin, ListView):
model = get_user_model() model = get_user_model()
template_name = 'auth/user_list.html' template_name = 'auth/user_list.html'

25
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')),
],
),
]

12
sapl/norma/models.py

@ -191,6 +191,18 @@ class NormaJuridica(models.Model):
update_fields=update_fields) 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() @reversion.register()
class AutoriaNorma(models.Model): class AutoriaNorma(models.Model):
autor = models.ForeignKey(Autor, autor = models.ForeignKey(Autor,

2
sapl/norma/tests/test_norma.py

@ -7,6 +7,7 @@ from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.norma.forms import (NormaJuridicaForm, NormaPesquisaSimplesForm, from sapl.norma.forms import (NormaJuridicaForm, NormaPesquisaSimplesForm,
NormaRelacionadaForm) NormaRelacionadaForm)
from sapl.norma.models import NormaJuridica, TipoNormaJuridica from sapl.norma.models import NormaJuridica, TipoNormaJuridica
from sapl.base.models import AppConfig
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
@ -15,6 +16,7 @@ def test_incluir_norma_submit(admin_client):
tipo = mommy.make(TipoNormaJuridica, tipo = mommy.make(TipoNormaJuridica,
sigla='T', sigla='T',
descricao='Teste') descricao='Teste')
config = mommy.make(AppConfig)
# Testa POST # Testa POST
response = admin_client.post(reverse('sapl.norma:normajuridica_create'), response = admin_client.post(reverse('sapl.norma:normajuridica_create'),

18
sapl/norma/views.py

@ -1,6 +1,8 @@
import re
import logging import logging
import re
import sapl
import weasyprint
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist 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.base import RedirectView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django_filters.views import FilterView from django_filters.views import FilterView
import weasyprint
import sapl
from sapl.base.models import AppConfig from sapl.base.models import AppConfig
from sapl.compilacao.views import IntegracaoTaView from sapl.compilacao.views import IntegracaoTaView
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, 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, from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm,
NormaPesquisaSimplesForm, NormaRelacionadaForm, AutoriaNormaForm) NormaPesquisaSimplesForm, NormaRelacionadaForm, AutoriaNormaForm)
from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada, from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada,
TipoNormaJuridica, TipoVinculoNormaJuridica, AutoriaNorma) TipoNormaJuridica, TipoVinculoNormaJuridica, AutoriaNorma, NormaEstatisticas)
# LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '') # LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '')
@ -190,7 +190,13 @@ class NormaCrud(Crud):
return reverse('%s:%s' % (namespace, 'norma_pesquisa')) return reverse('%s:%s' % (namespace, 'norma_pesquisa'))
class DetailView(Crud.DetailView): 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): class DeleteView(Crud.DeleteView):
@ -225,7 +231,7 @@ class NormaCrud(Crud):
class ListView(Crud.ListView, RedirectView): class ListView(Crud.ListView, RedirectView):
def get_redirect_url(self, *args, **kwargs): 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')) return reverse('%s:%s' % (namespace, 'norma_pesquisa'))
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):

2
sapl/rules/map_rules.py

@ -139,6 +139,7 @@ rules_group_norma = {
(norma.NormaRelacionada, __base__), (norma.NormaRelacionada, __base__),
(norma.AnexoNormaJuridica, __base__), (norma.AnexoNormaJuridica, __base__),
(norma.AutoriaNorma, __base__), (norma.AutoriaNorma, __base__),
(norma.NormaEstatisticas, __base__),
# Publicacao está com permissão apenas para norma e não para matéria # 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 # 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.AssuntoNorma, __base__),
(norma.TipoNormaJuridica, __base__), (norma.TipoNormaJuridica, __base__),
(norma.TipoVinculoNormaJuridica, __base__), (norma.TipoVinculoNormaJuridica, __base__),
(norma.NormaEstatisticas, __base__),
(parlamentares.Legislatura, __base__), (parlamentares.Legislatura, __base__),
(parlamentares.SessaoLegislativa, __base__), (parlamentares.SessaoLegislativa, __base__),

64
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 %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.base:estatisticas_acesso' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
<b>PARÂMETROS DE PESQUISA:<br /></b>
&emsp;Ano: {{ ano }} <br />
<br/>
{% if normas_mes|length == 0 %}
<br>
<h3>{% trans 'Não foi encontrada nenhuma norma com os parâmetros buscados.'%}</h3>
{% elif normas_mes|length == meses_sem_acesso|length %}
<br>
<h3>{% trans 'Nenhuma norma teve acesso neste ano.'%}</h3>
{% 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>
{% if not mes in meses_sem_acesso %}
<table class="table table-bordered table-hover" style="width:100%; margin-bottom: 30px;">
<thead class="thead-default" >
<tr class="active">
<th>Norma</th>
<th>Ementa</th>
<th>Acessos</th>
</tr>
</thead>
<tbody>
{% for n in normas %}
{% if n.1 > 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>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
{% else %}
<h3 style="text-align:center;">{% trans 'Nenhuma norma deste mês teve acessos.'%}</h3>
<br><br>
{% endif %}
</div>
{% endfor %}
{% endif %}
{% endif %}
{% endblock base_content %}

2
sapl/templates/base/RelatorioHistoricoTramitacao_filter.html

@ -30,7 +30,7 @@
<td><a href="{% url 'sapl.materia:tramitacao_list' materia.pk %}"> <td><a href="{% url 'sapl.materia:tramitacao_list' materia.pk %}">
{{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} {{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a></td> </a></td>
<td>{{materia.ementa}}</td> <td>{{materia.ementa}}<br>{{materia.observacao}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

2
sapl/templates/base/RelatorioMateriasPorAutor_filter.html

@ -51,7 +51,7 @@
<td><a href="{% url 'sapl.materia:materialegislativa_detail' materia.pk %}"> <td><a href="{% url 'sapl.materia:materialegislativa_detail' materia.pk %}">
{{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a></td> </a></td>
<td>{% autoescape off %}{{materia.ementa}}{% endautoescape %}</td> <td>{% autoescape off %}{{materia.ementa}}<br>{{materia.observacao}}{% endautoescape %}</td>
<td> <td>
{% if materia.autoria_set.first != materia.autoria_set.last %} {% if materia.autoria_set.first != materia.autoria_set.last %}
{% for autor in materia.autoria_set.all %} {% for autor in materia.autoria_set.all %}

67
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 %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.base:normas_por_mes' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
<b>PARÂMETROS DE PESQUISA:<br /></b>
&emsp;Ano: {{ ano }} <br />
<br/>
{% if normas_mes|length == 0 %}
<br>
<h3>{% trans 'Não foi encontrada nenhuma norma com os parâmetros buscados.'%}</h3>
{% endif %}
{% 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: 0px;">
<thead class="thead-default" >
<tr class="active">
{% for k, v in quant_normas_mes.items %}
{% if k == mes %}
{% if v > 1 %}
<th>Quantidade encontrada no mês: {{ v }} normas.</th>
{% else %}
<th>Quantidade encontrada no mês: 1 norma.</th>
{% endif %}
{% endif %}
{% endfor %}
</tr>
</thead>
</table>
<table class="table table-bordered table-hover" style="width:100%; margin-bottom: 30px;">
<thead class="thead-default" >
<tr class="active">
<th>Norma</th>
<th>Ementa</th>
</tr>
</thead>
<tbody>
{% for n in normas %}
<tr>
<td><a href="{% url 'sapl.norma:normajuridica_detail' n.pk %}">
{{n.tipo.descricao}} - {{n.tipo.sigla}} {{n.numero}}/{{n.ano}}
</a></td>
<td>{{n.ementa}}<br>{{n.observacao}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
{% endif %}
{% endblock base_content %}

57
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 %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.base:normas_por_vigencia' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
<b>PARÂMETROS DE PESQUISA:<br /></b>
&emsp;Ano: {{ ano }} <br />
&emsp;Vigência: {{ vigencia }} <br />
{% if object_list %}
<br/>
{% if object_list|length > 1 %}
<h3>Foram encontradas {{object_list|length}} normas.</h3>
{% else %}
<h3>Foi encontrada 1 norma.</h3>
{% endif %}
<br/>
<table class="table table-bordered table-hover" style="width:100%">
<thead class="thead-default" >
<tr class="active">
<th>Norma</th>
<th>Ementa</th>
</tr>
</thead>
<tbody>
{% for norma in object_list %}
<tr>
<td><a href="{% url 'sapl.norma:normajuridica_detail' norma.pk %}">
{{norma.tipo.descricao}} - {{norma.tipo.sigla}} {{norma.numero}}/{{norma.ano}}
</a></td>
<td>{{norma.ementa}}<br>{{norma.observacao}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<table class="table table-bordered table-hover" style="margin-top:30px;">
<thead class="thead-default" >
<tr class="active">
<th> Não foi encontrada nenhuma norma com os parâmetros buscados.</th>
</tr>
</thead>
</table>
{% endif %}
<br>
<h3>Estatísticas das normas do ano:</h3><br>
<h3>{{quant_vigente}} vigente(s) / {{quant_nao_vigente}} não vigente(s)</h3>
{% endif %}
{% endblock base_content %}

3
sapl/templates/base/layouts.yaml

@ -23,6 +23,9 @@ AppConfig:
{% trans 'Textos Articulados' %}: {% trans 'Textos Articulados' %}:
- texto_articulado_proposicao texto_articulado_materia texto_articulado_norma - texto_articulado_proposicao texto_articulado_materia texto_articulado_norma
{% trans 'Estatísticas de acesso' %}:
- estatisticas_acesso_normas
{% trans 'Assinaturas' %}: {% trans 'Assinaturas' %}:
- assinatura_ata - assinatura_ata

14
sapl/templates/base/relatorios_list.html

@ -48,6 +48,20 @@
<td><a href="{% url 'sapl.base:audiencia' %}">Audiência Pública</a></td> <td><a href="{% url 'sapl.base:audiencia' %}">Audiência Pública</a></td>
<td> Audiência Pública com o tipo. </td> <td> Audiência Pública com o tipo. </td>
</tr> </tr>
<tr>
<td><a href="{% url 'sapl.base:normas_por_mes' %}">Normas por mês</a></td>
<td> Normas publicadas por mês. </td>
</tr>
<tr>
<td><a href="{% url 'sapl.base:normas_por_vigencia' %}">Normas por vigência</a></td>
<td> Normas vigentes ou não vigentes. </td>
</tr>
{% if estatisticas_acesso_normas %}
<tr>
<td><a href="{% url 'sapl.base:estatisticas_acesso' %}">Estatísticas de acesso de Normas.</a></td>
<td> Normas por acesso. </td>
</tr>
{% endif %}
</tbody> </tbody>
</table> </table>
</fieldset> </fieldset>

Loading…
Cancel
Save