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. 16
      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.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)

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')),
('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'),

16
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'),

159
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'

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)
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,

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

16
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):

2
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__),

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 %}">
{{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a></td>
<td>{{materia.ementa}}</td>
<td>{{materia.ementa}}<br>{{materia.observacao}}</td>
</tr>
{% endfor %}
</tbody>

2
sapl/templates/base/RelatorioMateriasPorAutor_filter.html

@ -51,7 +51,7 @@
<td><a href="{% url 'sapl.materia:materialegislativa_detail' materia.pk %}">
{{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a></td>
<td>{% autoescape off %}{{materia.ementa}}{% endautoescape %}</td>
<td>{% autoescape off %}{{materia.ementa}}<br>{{materia.observacao}}{% endautoescape %}</td>
<td>
{% if materia.autoria_set.first != materia.autoria_set.last %}
{% 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' %}:
- texto_articulado_proposicao texto_articulado_materia texto_articulado_norma
{% trans 'Estatísticas de acesso' %}:
- estatisticas_acesso_normas
{% trans 'Assinaturas' %}:
- 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> Audiência Pública com o tipo. </td>
</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>
</table>
</fieldset>

Loading…
Cancel
Save